package com.aipp.mall.common.config;

import org.apache.hc.client5.http.HttpRoute;
import org.apache.hc.client5.http.classic.HttpClient;
import org.apache.hc.client5.http.config.ConnectionConfig;
import org.apache.hc.client5.http.config.RequestConfig;
import org.apache.hc.client5.http.cookie.StandardCookieSpec;
import org.apache.hc.client5.http.impl.classic.HttpClientBuilder;
import org.apache.hc.client5.http.impl.io.PoolingHttpClientConnectionManager;
import org.apache.hc.client5.http.socket.ConnectionSocketFactory;
import org.apache.hc.client5.http.socket.PlainConnectionSocketFactory;
import org.apache.hc.client5.http.ssl.SSLConnectionSocketFactory;
import org.apache.hc.core5.http.HttpHost;
import org.apache.hc.core5.http.config.Registry;
import org.apache.hc.core5.http.config.RegistryBuilder;
import org.apache.hc.core5.util.TimeValue;
import org.apache.hc.core5.util.Timeout;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.client.ClientHttpRequestFactory;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.web.client.RestTemplate;

/**
 * @author cc
 */
@Configuration
public class RestTemplateConfig {
    // 从连接池获取连接的超时时间，一般设置为较短；
    @Value("${http-pool.connection-request-timeout}")
    private long connectionRequestTimeout;

    // 连接超时时间
    @Value("${http-pool.connection-timeout}")
    private long connectionTimeout;

    // 完成连接后，socket通信超时时间
    @Value("${http-pool.socket-timeout}")
    private int socketTimeout;

    // 单host（可以理解为单域名）最大并发数
    @Value("${http-pool.max-per-route}")
    private int maxPerRoute;

    // 连接池最大连接数
    @Value("${http-pool.max-total}")
    private int maxTotal;

    @Bean
    public RestTemplate restTemplate() {
        return new RestTemplate(httpRequestFactory());
    }

    @Bean
    public ClientHttpRequestFactory httpRequestFactory() {
        return new HttpComponentsClientHttpRequestFactory(httpClient());
    }

    @Bean
    public HttpClient httpClient() {
        Registry<ConnectionSocketFactory> socketFactoryRegistry = RegistryBuilder.<ConnectionSocketFactory>create()
                .register("http", PlainConnectionSocketFactory.getSocketFactory())
                .register("https", SSLConnectionSocketFactory.getSocketFactory())
                .build();
        PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager(socketFactoryRegistry);

        connectionManager.setDefaultConnectionConfig(ConnectionConfig.custom()
                // 与服务端建立连接超时时间
                .setConnectTimeout(Timeout.ofSeconds(connectionTimeout))
                // 设置套接字超时时间，即等待响应数据的超时时间。
                .setSocketTimeout(Timeout.ofSeconds(socketTimeout))
                // 连接验证间隔时间。当一个连接在池中空闲时间超过此值时，连接将被验证是否可用
                .setValidateAfterInactivity(TimeValue.ofSeconds(10))
                // 定义连接可以保持活动状态或执行请求的总时间跨度。
                .setTimeToLive(TimeValue.ofHours(1))
                .build());
        // 设置整个连接池最大连接数 根据自己的场景决定
        // 路由是对maxTotal的细分
        // 为可以保留在池中或由连接管理器租用的持久连接配置总的最大或每条路由限制。
        connectionManager.setMaxTotal(maxTotal);
        connectionManager.setDefaultMaxPerRoute(maxPerRoute);
        connectionManager.setMaxPerRoute(new HttpRoute(new HttpHost("somehost", 80)), 20);
        RequestConfig requestConfig = RequestConfig.custom()
                .setCookieSpec(StandardCookieSpec.STRICT)
                .setExpectContinueEnabled(true).build();
        return HttpClientBuilder.create().setDefaultRequestConfig(requestConfig).setConnectionManager(connectionManager).build();
    }

}
